{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 0, Batch: 0, Loss: 3.4368724822998047, Accuracy: 0.03125\n",
      "Epoch: 0, Batch: 100, Loss: 0.29942241311073303, Accuracy: 0.7589727722772277\n",
      "Epoch: 0, Batch: 200, Loss: 0.3328148424625397, Accuracy: 0.8422730099502488\n",
      "Epoch: 0, Batch: 300, Loss: 0.11022641509771347, Accuracy: 0.8775955149501661\n",
      "Epoch: 0, Batch: 400, Loss: 0.354048490524292, Accuracy: 0.8966645885286783\n",
      "Epoch: 0, Batch: 500, Loss: 0.24132534861564636, Accuracy: 0.9088385728542914\n",
      "Epoch: 0, Batch: 600, Loss: 0.04527866840362549, Accuracy: 0.9181832362728786\n",
      "Epoch: 0, Batch: 700, Loss: 0.12166465818881989, Accuracy: 0.9252630171184023\n",
      "Epoch: 0, Batch: 800, Loss: 0.1747284233570099, Accuracy: 0.930126404494382\n",
      "Epoch: 0, Batch: 900, Loss: 0.06873676180839539, Accuracy: 0.9347946725860156\n",
      "Epoch: 1, Batch: 0, Loss: 0.09331785142421722, Accuracy: 0.9363845231752796\n",
      "Epoch: 1, Batch: 100, Loss: 0.03929222375154495, Accuracy: 0.9400577756379394\n",
      "Epoch: 1, Batch: 200, Loss: 0.108972929418087, Accuracy: 0.9429485068072024\n",
      "Epoch: 1, Batch: 300, Loss: 0.15025097131729126, Accuracy: 0.9456499798142914\n",
      "Epoch: 1, Batch: 400, Loss: 0.0603095181286335, Accuracy: 0.9479011019798281\n",
      "Epoch: 1, Batch: 500, Loss: 0.04927895963191986, Accuracy: 0.9500673444560306\n",
      "Epoch: 1, Batch: 600, Loss: 0.09085074067115784, Accuracy: 0.9519621384465389\n",
      "Epoch: 1, Batch: 700, Loss: 0.011017883196473122, Accuracy: 0.9535112145254806\n",
      "Epoch: 1, Batch: 800, Loss: 0.03214292973279953, Accuracy: 0.9548101811906816\n",
      "Epoch: 1, Batch: 900, Loss: 0.04458389803767204, Accuracy: 0.9562907941256459\n",
      "Test Accuracy: 0.9586\n",
      "预测结果为: 8\n"
     ]
    }
   ],
   "source": [
    "import paddle\n",
    "import paddle.nn as nn\n",
    "from paddle.vision.datasets import MNIST\n",
    "from paddle.vision.transforms import Normalize\n",
    "from paddle.metric import Accuracy\n",
    "from paddle.optimizer import Adamax\n",
    "\n",
    "\n",
    "transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')\n",
    "\n",
    "\n",
    "train_dataset = MNIST(mode='train', transform=transform)\n",
    "test_dataset = MNIST(mode='test', transform=transform)\n",
    "\n",
    "class LeNet5(nn.Layer):\n",
    "    def __init__(self):\n",
    "        super(LeNet5, self).__init__()\n",
    "        self.conv1 = nn.Conv2D(in_channels=1, out_channels=6, kernel_size=5, stride=1)\n",
    "        self.pool1 = nn.MaxPool2D(kernel_size=2, stride=2)\n",
    "        self.conv2 = nn.Conv2D(in_channels=6, out_channels=16, kernel_size=5, stride=1)\n",
    "        self.pool2 = nn.MaxPool2D(kernel_size=2, stride=2)\n",
    "        self.fc1 = nn.Linear(in_features=16*4*4, out_features=120)\n",
    "        self.fc2 = nn.Linear(in_features=120, out_features=84)\n",
    "        self.fc3 = nn.Linear(in_features=84, out_features=10)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = self.conv1(x)\n",
    "        x = paddle.nn.functional.relu(x)\n",
    "        x = self.pool1(x)\n",
    "        x = self.conv2(x)\n",
    "        x = paddle.nn.functional.relu(x)\n",
    "        x = self.pool2(x)\n",
    "        x = paddle.flatten(x, start_axis=1)\n",
    "        x = self.fc1(x)\n",
    "        x = paddle.nn.functional.relu(x)\n",
    "        x = self.fc2(x)\n",
    "        x = paddle.nn.functional.relu(x)\n",
    "        x = self.fc3(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "model = LeNet5()\n",
    "\n",
    "\n",
    "optimizer = Adamax(learning_rate=0.01, parameters=model.parameters())\n",
    "loss_fn = nn.CrossEntropyLoss()\n",
    "metric = Accuracy()\n",
    "\n",
    "\n",
    "\n",
    "def train(model, dataset, epoch):\n",
    "    model.train()\n",
    "    loader = paddle.io.DataLoader(dataset, batch_size=64, shuffle=True)\n",
    "    for batch_id, (data, label) in enumerate(loader):\n",
    "        output = model(data)\n",
    "        loss = loss_fn(output, label)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        optimizer.clear_grad()\n",
    "        \n",
    "        # 计算准确率\n",
    "        correct = metric.compute(output, label)\n",
    "        metric.update(correct)\n",
    "        \n",
    "        if batch_id % 100 == 0:\n",
    "            acc = metric.accumulate()\n",
    "            print(f\"Epoch: {epoch}, Batch: {batch_id}, Loss: {loss.numpy()[0]}, Accuracy: {acc}\")\n",
    "\n",
    "\n",
    "for epoch in range(2):\n",
    "    train(model, train_dataset, epoch)\n",
    "\n",
    "\n",
    "def test(model, dataset):\n",
    "    model.eval()\n",
    "    loader = paddle.io.DataLoader(dataset, batch_size=64, shuffle=False)\n",
    "    for batch_id, (data, label) in enumerate(loader):\n",
    "        output = model(data)\n",
    "        correct = metric.compute(output, label)\n",
    "        metric.update(correct)\n",
    "    acc = metric.accumulate()\n",
    "    print(f\"Test Accuracy: {acc}\")\n",
    "\n",
    "test(model, test_dataset)\n",
    "\n",
    "\n",
    "\n",
    "model_path = \"甄一德_model\"\n",
    "paddle.save(model.state_dict(), model_path + \".pdparams\")\n",
    "\n",
    "\n",
    "\n",
    "loaded_model = LeNet5()\n",
    "loaded_model.set_state_dict(paddle.load(model_path + \".pdparams\"))\n",
    "loaded_model.eval()\n",
    "\n",
    "\n",
    "from PIL import Image\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "def preprocess_image(image_path):\n",
    "    img = Image.open(image_path).convert('L')  \n",
    "    img = img.resize((28, 28))  \n",
    "    img = np.array(img).astype('float32')  \n",
    "    img = (img - 127.5) / 127.5  \n",
    "    img = img[np.newaxis, np.newaxis, :, :]  \n",
    "    return paddle.to_tensor(img)\n",
    "\n",
    "\n",
    "input_tensor = preprocess_image(\"9.jpg\")\n",
    "\n",
    "\n",
    "output = loaded_model(input_tensor)\n",
    "prediction = paddle.argmax(output).numpy()[0]\n",
    "\n",
    "print(f\"预测结果为: {prediction}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
